#include "../ocl/queue.h"


int  ocl_queue_load( ocl_queue *q, const ocl_context *context, cl_device_id device_id,  cl_command_queue_properties pp )
{
	
	assert( q != NULL );
	assert( context != NULL );
	
	ocl_errno = CL_SUCCESS;
	memset( q, 0, sizeof(ocl_queue) );
	if( ocl_logfile ) fprintf( ocl_logfile, "[ocl_queue_load]\n");
	q->handle = clCreateCommandQueue( context->handle, device_id, pp, & ocl_errno );
	if( CL_SUCCESS != ocl_errno )
	{
		return -1;
	}
	
#define OCL_QUEUE_INFO(FIELD,TYPE) if( CL_SUCCESS != ( ocl_errno = clGetCommandQueueInfo( q->handle, CL_QUEUE_##FIELD, sizeof(TYPE), & q->FIELD, NULL ) ) ) goto ERROR
	
	OCL_QUEUE_INFO(DEVICE,cl_device_id);
	OCL_QUEUE_INFO(PROPERTIES,cl_command_queue_properties);
	
	return 0;
	
ERROR:
	ocl_queue_quit(q);
	return -1;
}

void ocl_queue_quit( ocl_queue *q )
{
	if( q )
	{
		if( ocl_logfile ) fprintf( ocl_logfile, "[ocl_queue_quit]\n");
		(void) clReleaseCommandQueue( q->handle );
		memset( q, 0, sizeof(ocl_queue) );
	}
}

int ocl_enqueue_task( ocl_queue *q, ocl_kernel *kernel, OCL_EVENTS_DECL )
{
	assert( q );
	assert( kernel );
	assert( kernel->FUNCTION_NAME );
	if( ocl_logfile ) fprintf( ocl_logfile, "[ocl_enqueue_task] '%s'\n", kernel->FUNCTION_NAME );
	if( CL_SUCCESS != ( ocl_errno = clEnqueueTask(q->handle, kernel->handle, OCL_EVENTS_IMPL ) ) )
		return -1;
	return 0;
}

int ocl_enqueue_barrier( ocl_queue *q )
{
	assert( q );
	if( CL_SUCCESS != ( ocl_errno = clEnqueueBarrier( q->handle ) ) )
		return -1;
	return 0;
}

int ocl_flush(  ocl_queue *q )
{
	assert( q );
	if( CL_SUCCESS != ( ocl_errno = clFlush( q->handle ) ) )
		return -1;
	return 0;
	
}

int ocl_finish( ocl_queue *q )
{
	if( CL_SUCCESS != ( ocl_errno = clFinish( q->handle ) ) )
		return -1;
	return 0;
}

int ocl_enqueue_read_buffer(ocl_queue  *q,
						   ocl_buffer *buffer,
						   cl_bool     blocking_read,
						   size_t      offset,
						   size_t      cb,
						   void       *ptr, 
						   OCL_EVENTS_DECL )
{
	assert( q );
	assert( buffer );
	if( CL_SUCCESS != ( ocl_errno = clEnqueueReadBuffer(q->handle, 
														buffer->handle, 
														blocking_read, 
														offset,
														cb,
														ptr,
														OCL_EVENTS_IMPL) ) )
		return -1;
	return 0;
}


int ocl_enqueue_write_buffer(ocl_queue  *q,
							ocl_buffer *buffer,
							cl_bool     blocking_read,
							size_t      offset,
							size_t      cb,
							const void *ptr, 
							OCL_EVENTS_DECL )
{
	assert( q );
	assert( buffer );
	if( CL_SUCCESS != ( ocl_errno = clEnqueueWriteBuffer(q->handle, 
														 buffer->handle, 
														 blocking_read, 
														 offset,
														 cb,
														 ptr,
														 OCL_EVENTS_IMPL) ) )
		return -1;
	return 0;
}

int ocl_enqueue_ndrange_kernel( ocl_queue   *q,
							  ocl_kernel   *kernel,
							  cl_uint       work_dim,
							  const size_t *global_work_offset,
							  const size_t *global_work_size,
							  const size_t *local_work_size,
							  OCL_EVENTS_DECL )
{
	assert( q );
	assert( kernel );
	if( CL_SUCCESS != ( ocl_errno = clEnqueueNDRangeKernel(q->handle,
														  kernel->handle, 
														  work_dim, 
														  global_work_offset, 
														  global_work_size, 
														  local_work_size, 
														  OCL_EVENTS_IMPL) ) )
	{
		return -1;
	}
	return 0;
}


